#include <iostream>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>

//管道的四种特殊情况
//1、写端不关，写端不写：管道中数据为空, 读端就会被阻塞->管道自带同步机制

//2、读端不关，读端不读：管道写满就结束写操作
// int main()
// {
//     int pipefd[2] = {0};
//     int n = pipe(pipefd); // 1、创建管道

//     pid_t id = fork();
//     if (id < 0)
//     {
//         perror("fork");
//         exit(1);
//     }
//     if (id == 0)
//     {
//         // 子进程
//         // 关闭不需要端口
//         close(pipefd[0]); // 子进程执行写操作，关闭读端口
//         std::string str = "hello father, I'm son, ";
//         std::string self = std::to_string(getpid());
//         int cnt = 1;
//         while (true)
//         {
//             // 写操作
//             char ch = 'A';
//             write(pipefd[1], &ch, 1);
//             std::cout << " count: " << cnt++ << std::endl;
//         }
//     }
//     else
//     {
//         // 父进程
//         // 关闭不需要端口
//         close(pipefd[1]); // 父进程执行读操作，关闭写端口
//         while (true)
//         {}

//         pid_t rid = waitpid(id, nullptr, 0);
//         (void)rid;
//     }

//     return 0;
// }

//3、写端不写，写端关闭
//read会读到返回值为0，表示读到文件结尾
// int main()
// {
//     int pipefd[2] = {0};
//     int n = pipe(pipefd); // 1、创建管道
//     pid_t id = fork();
//     if (id < 0)
//     {
//         perror("fork");
//         exit(1);
//     }
//     if (id == 0)
//     {
//         // 子进程
//         // 关闭不需要端口
//         close(pipefd[0]); // 子进程执行写操作，关闭读端口
//         std::string str = "hello father, I'm son, ";
//         std::string self = std::to_string(getpid());
//         int cnt = 0;
//         std::string message = str + ", " + self + ", ";
//         while (cnt < 10)
//         {
//             // 写操作
//             sleep(1);
//             char ch = 'A' + cnt;
//             write(pipefd[1], &ch, 1);
//             cnt++;
//         }
//         close(pipefd[1]);//写关闭
//         std::cout << "写端关闭" << std::endl;
//         sleep(3);
//     }
//     else
//     {
//         // 父进程
//         // 关闭不需要端口
//         close(pipefd[1]); // 父进程执行读操作，关闭写端口
//         while (true)
//         {
//             char ch;
//             ssize_t n = read(pipefd[0], &ch, 1);//读取数据
//             if (n > 0)
//             {
//                 std::cout << "clinet->father: " << ch << std::endl;
//             }
//             else if(n == 0)
//             {
//                 std::cout << "return val: " << n << std::endl;
//                 sleep(1);
//             }
//             else
//             {
//                 std::cout << "error" << std::endl;
//             }
//         }

//         pid_t rid = waitpid(id, nullptr, 0);
//         (void)rid;
//     }

//     return 0;
// }

//4、读端关闭，写端正常
//os会自动杀死写进程(信号13)，os不做无用工作
int main()
{
    int pipefd[2] = {0};
    int n = pipe(pipefd); // 1、创建管道

    pid_t id = fork();
    if (id < 0)
    {
        perror("fork");
        exit(1);
    }
    if (id == 0)
    {
        // 子进程
        // 关闭不需要端口
        close(pipefd[0]); // 子进程执行写操作，关闭读端口
        std::string str = "hello father, I'm son, ";
        std::string self = std::to_string(getpid());
        int cnt = 1;
        std::string message = str + ", " + self + ", ";
        while (true)
        {
            // 写操作
            message += std::to_string(cnt++);
            write(pipefd[1], message.c_str(), message.size());
            sleep(1);
        }
    }
    else
    {
        // 父进程
        // 关闭不需要端口
        close(pipefd[1]); // 父进程执行读操作，关闭写端口
        while (true)
        {
            char inbuffer[1024] = {0};
            ssize_t n = read(pipefd[0], inbuffer, sizeof(inbuffer) - 1);//读取数据
            if (n > 0)
            {
                inbuffer[n] = 0;
                std::cout << "clinet->father: " << inbuffer << std::endl;
            }
            break;
        }
        close(pipefd[0]);//关闭读端
        std::cout << "读端关闭" << std::endl;
        int status = 0;
        pid_t rid = waitpid(id, &status, 0);

        if(rid > 0)
        {
            int exitcode = (status >> 8) & 0xff;//退出码
            int exitsign = (status & 0x7f);//退出信号：13
            std::cout<< "wait success, rid: " << rid << " , exit code: " << exitcode << " , exit sign: " << exitsign << std::endl;
        }

    }

    return 0;
}